using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.IO;
using System.Xml;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Collections.Specialized;
using System.Web.Caching;

namespace MCromwell.StaffIntranet.UI
{
    public abstract class PageAuthenticationModule : IHttpModule
    {
        private CacheDependency fileDependency;

        public void Init(HttpApplication context)
        {
            context.BeginRequest += new EventHandler(CheckAuthentication);
        }

        protected abstract bool AllowAccess();
        
        void CheckAuthentication(object sender, EventArgs e)
        {
            NameValueCollection configSettings = (NameValueCollection)ConfigurationManager.GetSection("requestprotection");
            XmlDocument configXml = new XmlDocument();
            HttpApplication application = (HttpApplication)sender;

            string cacheSetting = configSettings["requestprotection.caching.enabled"];
            bool cacheXml =((string.IsNullOrEmpty(cacheSetting)) ? false : cacheSetting.Equals("yes",StringComparison.InvariantCultureIgnoreCase));
            string executionRoot = application.Request.PhysicalApplicationPath;
            string xmlFilePath = Path.Combine(executionRoot, string.IsNullOrEmpty(configSettings["requestprotection.xmlfile"]) ? "protect.requests.xml" : configSettings["requestprotection.xmlfile"]);
            string key = (string.IsNullOrEmpty(configSettings["requestprotection.caching.key"]) ? "protect.requests.key" : configSettings["requestprotection.caching.key"]);

            if (cacheXml)
            {
                configXml = application.Context.Cache[key] as XmlDocument;
                if (configXml != null)
                {
                    PerformCheckAgainstXml(configXml, application);
                }
                else
                {
                    configXml = new XmlDocument();
                    LoadXmlFromFile(configXml, application, xmlFilePath, key);
                    CacheXml(configXml, application, xmlFilePath, key);
                    PerformCheckAgainstXml(configXml, application);
                }
            }
            else 
            {
                configXml = new XmlDocument();
                LoadXmlFromFile(configXml, application, xmlFilePath, key);
                PerformCheckAgainstXml(configXml, application);
            }
        }

        private void CacheXml(XmlDocument configXml, HttpApplication application, string xmlFilePath, string key)
        {
            fileDependency = new CacheDependency(xmlFilePath);
            application.Context.Cache.Insert(key, configXml, fileDependency);
        }

        private void LoadXmlFromFile(XmlDocument configXml, HttpApplication application, string xmlFilePath, string key)
        {
            
            if (File.Exists(xmlFilePath))
            {
                configXml.Load(xmlFilePath);
            }
        }

        private void PerformCheckAgainstXml(XmlDocument configXml, HttpApplication application)
        {
            XmlNodeList requestElements = configXml.SelectNodes("protect/request");

            foreach (XmlElement requestElement in requestElements)
            {
                string currentRequestUrl = application.Request.AppRelativeCurrentExecutionFilePath;
                string requestUrl = requestElement.GetAttribute("url");
                if (Regex.IsMatch(currentRequestUrl, requestUrl))
                {
                    if (!AllowAccess())
                    {
                        string redirect = requestElement.GetAttribute("redirect");
                        application.Response.Redirect(redirect);
                    }
                }
            }
        }
    
        public void Dispose()
        {
        }
                
    }
        
}
